/*
 *  region.cc
 *  Untitled
 *
 *  Created by Ben Nolan on 2/11/08.
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 *
 */

#include "region.h"
#include "errors.h"
#include "tinyxml/ticpp.h"
#include "boost/foreach.hpp"
#include <sstream>
#include <fstream>

namespace Wonderland {

Region::~Region(){
	BOOST_FOREACH(NodeMapPair pair, nodes_){
		delete pair.second;
	}
}

/*
 * brief: Adds a node to the region
 */
void Region::addNode(Wonderland::Node* node){
	if(nodes_[node->guid_]){
		// Delete the current node I guess?
		
		//throw Wonderland::Errors::Fatal("Node " + node->guid_.toString() + " already exists in region");
	}

	nodes_[node->guid_] = node;
	dirtyNodes_[node->guid_] = node;
}

/*
 * brief: Returns a vector of all nodes contained within the AAB
 */
std::vector<Node*> Region::findNodesWithin(const AxisAlignedBox box){
	std::vector<Node*> nodes;
	
	BOOST_FOREACH(NodeMapPair pair, nodes_){
		if(box.contains(pair.second->getPosition())){
			nodes.push_back(pair.second);
		}
	}

	return nodes;
}

/*
 * brief: Get an string of the xml representation of a region
 *
 * Used by save().
 */
std::string Region::toString(){
	std::stringstream xml;
	ticpp::Element* el = toXml();
	xml << *el << std::endl;
	delete el;
	return xml.str();
}

/*
 * brief: Returns an xml element containing a representation of the region
 *
 * Used by toString();
 */
ticpp::Element* Region::toXml(){
    ticpp::Element* el = new ticpp::Element("region");
	
	BOOST_FOREACH(NodeMapPair pair, nodes_){
		ticpp::Element* node = pair.second->toXml();
		el->InsertEndChild(*node);
		delete node;
	}
	
	return el;
}

/*
 * brief: Save the region to disk in the xml representation
 *
 * Run occasionally to keep a backup of the region on disk.
 */
void Region::save(std::string fn){
	std::fstream fs(fn.c_str(), std::fstream::out);
	fs << toString();
	fs.close();
}

/*
 * @brief Read a file into a string
 *
 * Used internally by load()
 */
inline std::string slurp(std::string filename) {
  std::ifstream input(filename.c_str());
  std::stringstream sstr;
  sstr << input.rdbuf();
  return sstr.str();
}

/*
 * @brief Load the region from a region.xml file
 *
 */
void Region::load(std::string filename){
	std::string xml = slurp(filename);

	ticpp::Document doc;

	try{
		doc.Parse(xml.c_str());
	}catch(ticpp::Exception& ex){
		throw Wonderland::Errors::BadSerialization();
	}
	
	// Check we have a root element
	if(!doc.FirstChildElement()){
		throw Wonderland::Errors::BadSerialization();
	}
	
	// Check we have nodes to process..
	if(doc.FirstChildElement()->FirstChildElement()){
		ticpp::Element *needle = doc.FirstChildElement()->FirstChildElement();
		
		// Process nodes..
		while(needle){
			if(needle->Value() == (std::string) "node"){
				addNode(new Node(needle));
			}
			
			try{
				needle = needle->NextSiblingElement();
			}catch(ticpp::Exception err){
				return;
			}
		}
	}
	
}

}
